﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using Grundy.CryptographicServices;
using Grundy.Message;

using Grundy.TestHelpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Grundy.Common;
using System.Linq;
using Newtonsoft.Json;
using ServiceStack.Text;
using JsonSerializer = Newtonsoft.Json.JsonSerializer;

namespace Grundy.Entity.Tests
{
    [TestClass]
    public class SerializationTests
    {
        private ObjectMother _objectMother = new ObjectMother();
        
        [TestMethod]
        public void Should_serialize_and_deserialize_xml()
        {
            Action action = () =>
                                {
                                    var customerEntitlement = GetCustomerEntitlement();
                                    var ce = customerEntitlement.Serialize();
                                    Container container = GetContainer(ce);
                                    var c = container.Serialize();
                                    var cLoaded = c.Deserialize<Container>();
                                    var ceLoaded = cLoaded.Payload.Deserialize<CustomerEntitlement>();
                                    Assert.AreEqual(customerEntitlement.Id, ceLoaded.Id);
                                    Assert.AreEqual(customerEntitlement.LicenseEntitlements.Count, ceLoaded.LicenseEntitlements.Count);
                                    Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().License.Type, ceLoaded.LicenseEntitlements.First().License.Type);
                                    Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().Node.Identifiers.First(), ceLoaded.LicenseEntitlements.First().Node.Identifiers.First());
                                };

            var now = DateTime.Now;
            action.Invoke();
            Console.WriteLine(ExtensionMethods.FormatWith("First serialization took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));

            now = DateTime.Now;
            Enumerable.Range(0,1000).ToList().ForEach(i => action.Invoke());
            Console.WriteLine(ExtensionMethods.FormatWith("Other serializations took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));
        }

        [TestMethod, Ignore]
        public void Should_serialize_and_deserialize_json_using_servicestack_text()
        {
            Action action = () =>
            {
                var customerEntitlement = GetCustomerEntitlement();
                var ce = new TypeSerializer<CustomerEntitlement>().SerializeToString(customerEntitlement);
                Container container = GetContainer(ce);
                var c = new TypeSerializer<Container>().SerializeToString(container);
                var cLoaded =  new TypeSerializer<Container>().DeserializeFromString(c);
                var ceLoaded = new TypeSerializer<CustomerEntitlement>().DeserializeFromString(cLoaded.Payload);
                Assert.AreEqual(customerEntitlement.Id, ceLoaded.Id);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.Count, ceLoaded.LicenseEntitlements.Count);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().License.Type, ceLoaded.LicenseEntitlements.First().License.Type);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().Node.Identifiers.First(), ceLoaded.LicenseEntitlements.First().Node.Identifiers.First());
            };

            var now = DateTime.Now;
            action.Invoke();
            Console.WriteLine(ExtensionMethods.FormatWith("First serialization took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));

            now = DateTime.Now;
            Enumerable.Range(0, 1000).ToList().ForEach(i => action.Invoke());
            Console.WriteLine(ExtensionMethods.FormatWith("Other serializations took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));
        }

        [TestMethod]
        public void Should_serialize_and_deserialize_json_using_json_net()
        {
            Action action = () =>
            {
                var serializer = JsonSerializer.Create(new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
                var buffer = new StringBuilder();
                
                var customerEntitlement = GetCustomerEntitlement();
                serializer.Serialize(new StringWriter(buffer), customerEntitlement);
                var ce = buffer.ToString();

                Container container = GetContainer(ce);
                buffer = buffer.Clear();
                serializer.Serialize(new StringWriter(buffer), container);
                var c = buffer.ToString();

                var cLoaded = (Container) serializer.Deserialize(new StringReader(c), typeof(Container));
                var ceLoaded = (CustomerEntitlement) serializer.Deserialize(new StringReader(cLoaded.Payload), typeof(CustomerEntitlement));
                Assert.AreEqual(customerEntitlement.Id, ceLoaded.Id);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.Count, ceLoaded.LicenseEntitlements.Count);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().License.Type, ceLoaded.LicenseEntitlements.First().License.Type);
                Assert.AreEqual(customerEntitlement.LicenseEntitlements.First().Node.Identifiers.First(), ceLoaded.LicenseEntitlements.First().Node.Identifiers.First());
            };

            var now = DateTime.Now;
            action.Invoke();
            Console.WriteLine(ExtensionMethods.FormatWith("First serialization took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));

            now = DateTime.Now;
            Enumerable.Range(0, 1000).ToList().ForEach(i => action.Invoke());
            Console.WriteLine(ExtensionMethods.FormatWith("Other serializations took {0} ms", DateTime.Now.Subtract(now).TotalMilliseconds));
        }

        private Container GetContainer(string ce)
        {
            return new Container{Algorithm = "http://RSA~", Provider = "RsaProvider", Signature = new byte[128].ToHexadecimalString(), Signee = ContainerSigneeType.Client, Payload = ce};
        }

        private CustomerEntitlement GetCustomerEntitlement()
        {
            var customerEntitlement = _objectMother.GetCustomerEntitlement(new List<LicenseEntitlement>
                                                                               {
                                                                                   _objectMother.GetLicenseEntitlement(_objectMother.GetProduct("Product Name 1", new [] {"Feature1", "Feature2"}),_objectMother.GetCountedFloatingLicense(12345)),
                                                                                   _objectMother.GetLicenseEntitlement(_objectMother.GetProduct("Product Name 2", new[] {"Feature1", "Feature2"}), _objectMother.GetNodeLockedLicense())
                                                                               }, _objectMother.GetCustomer("Ashish Sharma"));
            return customerEntitlement;
        }

        
    }
}